import type { ElementLocator } from '../element/service/types'
import {
  ElementSelectorDOMScopeType,
  ElementSelectorType,
  emptyJQuery,
  logger,
  SelectorSyntaxType,
} from '../types/constants'
import { SYMBOLS } from '../types/interfaces'
import { ToolKit } from './utils/toolkit'

export enum ElementSelectorReturnType {
  Element = 'element',
  JQueryElement = 'JQueryElement',
  NodeList = 'nodeList',
}

export enum ElementSelectorEngine {
  Native = 'native',
  Jquery = 'jquery',
  Auto = 'auto',
}

/**
 * 选择器性能优化配置
 */
export interface SelectorOptimizationConfig {
  useGetElementById?: boolean // 优先使用 getElementById
  useGetElementsByClassName?: boolean // 优先使用 getElementsByClassName
  useGetElementsByTagName?: boolean // 优先使用 getElementsByTagName
  cacheResults?: boolean // 缓存查询结果
  maxCacheSize?: number // 最大缓存大小
}

export interface ElementQueryOptions {
  domScope?: ElementSelectorDOMScopeType
  hostSelector?: string
  engine?: ElementSelectorEngine
  returnType?: ElementSelectorReturnType
  context?: Document | HTMLElement
}

export type ElementQueryResult = JQuery<HTMLElement> | HTMLElement | NodeList | null

/**
 * 元素查询服务
 */
export class ElementQuery {
  readonly name: string = 'ElementQuery'
  public static elementQuery: ElementQuery
  private readonly optimizationConfig: SelectorOptimizationConfig = {
    useGetElementById: true,
    useGetElementsByClassName: true,
    useGetElementsByTagName: true,
  }

  public static getInstance(): ElementQuery {
    if (!ElementQuery.elementQuery) {
      ElementQuery.elementQuery = new ElementQuery()
    }
    return ElementQuery.elementQuery
  }

  /**
   * 智能获取元素
   */
  queryElement(
    selector: string,
    options?: ElementQueryOptions,
  ): ElementQueryResult {
    const {
      engine = ElementSelectorEngine.Auto,
      returnType = ElementSelectorReturnType.JQueryElement,
      domScope = ElementSelectorDOMScopeType.Document,
      hostSelector = '',
      context = document,
    } = options || {}

    const locator = {
      domScope,
      hostSelector: ToolKit.string.safeString(hostSelector),
      selector: ToolKit.string.safeString(selector),
    }

    const selectorType = ToolKit.ui.element.detectSelectorType(selector)
    const finalEngine = engine === ElementSelectorEngine.Auto
      ? this.chooseOptimalEngine(selectorType)
      : engine

    try {
      let result: any = null

      switch (finalEngine) {
        case ElementSelectorEngine.Native:
          result = this.queryWithNativeAPI(locator, selectorType, returnType, context)
          break
        case ElementSelectorEngine.Jquery:
          result = this.queryWithJQuery(locator, selectorType, returnType, context)
          break
        default:
          throw new Error(`不支持的选择器引擎: ${finalEngine}`)
      }

      return result
    }
    catch (error) {
      logger.warn(`[${this.name}] 查询失败: ${selector}`, error)
      // 降级方案：使用 jQuery 查询
      return this.queryWithJQuery(locator, selectorType, returnType, context)
    }
  }

  /**
   * 使用原生 API 查询（性能最优）
   */
  private queryWithNativeAPI(
    locator: ElementLocator,
    selectorType: ElementSelectorType,
    returnType: ElementSelectorReturnType,
    context: Document | HTMLElement,
  ): HTMLElement | NodeList | HTMLCollection | null {
    const { domScope, hostSelector = '', selector } = locator

    // 类型守卫：检查是否为 Document
    const isDocumentContext = (ctx: Document | HTMLElement | ShadowRoot): ctx is Document => {
      return ctx.nodeType === Node.DOCUMENT_NODE
    }

    // 类型守卫：检查是否为 HTMLElement
    const isHTMLElementContext = (ctx: Document | HTMLElement | ShadowRoot): ctx is HTMLElement => {
      return ctx.nodeType === Node.ELEMENT_NODE
    }

    try {
      const queryContext = this.getQueryContext(domScope, hostSelector, context)
      if (!queryContext) {
        logger.warn(`[${this.name}] 无法获取查询上下文: ${domScope} ${hostSelector}`)
        return null
      }

      const handler = (element?: HTMLElement | null) => {
        const targetElement = element || queryContext.querySelector(selector)
        if (returnType === ElementSelectorReturnType.Element) {
          return targetElement as HTMLElement | null
        }
        else {
          return targetElement ? ToolKit.ui.element.createNodeListFromElement(targetElement) : null
        }
      }

      const collectionHandler = (elements: HTMLCollection) => {
        if (returnType === ElementSelectorReturnType.Element) {
          return elements.length > 0 ? elements[0] as HTMLElement : null
        }
        else {
          return elements.length > 0 ? elements : null
        }
      }

      const nodeListHandler = (nodeList: NodeList) => {
        if (returnType === ElementSelectorReturnType.Element) {
          return nodeList.length > 0 ? nodeList[0] as HTMLElement : null
        }
        else {
          return nodeList.length > 0 ? nodeList : null
        }
      }

      switch (selectorType) {
        case ElementSelectorType.Id: {
          if (this.optimizationConfig.useGetElementById && isDocumentContext(queryContext)) {
            const element = queryContext.getElementById(selector.slice(1))
            return handler(element)
          }
          else if (isHTMLElementContext(queryContext)) {
            // 在 HTMLElement 上下文中使用 querySelector
            return handler()
          }
          break
        }

        case ElementSelectorType.Class: {
          if (this.optimizationConfig.useGetElementsByClassName && (isDocumentContext(queryContext) || isHTMLElementContext(queryContext))) {
            const elements = queryContext.getElementsByClassName(selector.slice(1))
            return collectionHandler(elements)
          }
          break
        }

        case ElementSelectorType.Tag: {
          if (this.optimizationConfig.useGetElementsByTagName && (isDocumentContext(queryContext) || isHTMLElementContext(queryContext))) {
            const elements = queryContext.getElementsByTagName(selector)
            return collectionHandler(elements)
          }
          break
        }

        case ElementSelectorType.Multiple: {
          const nodeList = queryContext.querySelectorAll(selector)
          return nodeListHandler(nodeList)
        }

        case ElementSelectorType.Attribute:
        case ElementSelectorType.Mix:
        case ElementSelectorType.Complex:
        default:
          return handler()
      }

      return handler()
    }
    catch (error) {
      logger.warn(`[${this.name}] 原生 API 查询失败: ${selector}`, error)
      return null
    }
  }

  /**
   * 使用 jQuery 查询
   */
  private queryWithJQuery(
    locator: ElementLocator,
    selectorType: ElementSelectorType,
    returnType: ElementSelectorReturnType,
    context: Document | HTMLElement,
  ): JQuery<HTMLElement> | HTMLElement | null {
    const { domScope, hostSelector = '', selector } = locator

    try {
      const $queryContext = this.getJQueryQueryContext(domScope, hostSelector, context)
      if (!$queryContext || $queryContext.length === 0) {
        logger.warn(`[${this.name}] 无法获取 jQuery 查询上下文: ${domScope} ${hostSelector}`)
        return null
      }

      let $result: JQuery<HTMLElement>

      if (domScope === ElementSelectorDOMScopeType.ShadowRoot) {
        $result = this.queryShadowDOMWithJQuery(hostSelector, selector, $queryContext)
      }
      else {
        const handler = () => $(selector, $queryContext)
        switch (selectorType) {
          case ElementSelectorType.Complex: {
            try {
              // 复杂选择器：使用 find() 提高性能
              // 1）不包含 has() 伪类，因为存在 :has(>) 这种复杂情况，容易解析失败
              if (['>', '+', '~'].some(op => selector.includes(op)) && !ToolKit.ui.syntax.hasSelectorSyntax(selector, SelectorSyntaxType.HAS)) {
                // 使用正则表达式匹配第一个关系选择器
                const relationMatch = selector.match(/(.*?)([>+~])(.+)/)

                if (!relationMatch) {
                  $result = handler()
                }
                else {
                  const [, mainSelector, separator, remainingSelector] = relationMatch
                  const trimmedMain = mainSelector.trim()
                  const trimmedRemaining = remainingSelector.trim()

                  logger.debug(`[${this.name}] 复杂选择器解析结果`, {
                    selector,
                    trimmedMain,
                    trimmedRemaining,
                    separator,
                  })

                  // 根据分隔符选择不同的 jQuery 方法
                  switch (separator) {
                    case '>':
                      // 直接子元素
                      $result = $(trimmedMain, $queryContext).children(trimmedRemaining) ?? handler()
                      break
                    case '+':
                      // 相邻兄弟元素
                      $result = $(trimmedMain, $queryContext).next(trimmedRemaining) ?? handler()
                      break
                    case '~':
                      // 后续兄弟元素
                      $result = $(trimmedMain, $queryContext).nextAll(trimmedRemaining) ?? handler()
                      break
                    default:
                      $result = $(trimmedMain, $queryContext).find(trimmedRemaining) ?? handler()
                  }
                }
              }
              else {
                $result = handler()
              }
            }
            catch (error) {
              logger.notice(`[${this.name}] ${SYMBOLS.STATUS.WARNING} 复杂选择器解析失败: ${selector}`, error)
              $result = handler()
            }
            break
          }

          default:
            $result = handler()
        }
      }

      // 根据返回类型转换结果
      switch (returnType) {
        case ElementSelectorReturnType.JQueryElement:
          return $result
        case ElementSelectorReturnType.Element:
          return $result[0] || null
        case ElementSelectorReturnType.NodeList:
          return $result.length > 0 ? $result.toArray() as any : null
        default:
          return $result
      }
    }
    catch (error) {
      logger.warn(`[${this.name}] jQuery 查询失败: ${selector}`, error)
      return null
    }
  }

  /**
   * 获取查询上下文（根据 domScope 和 hostSelector）
   */
  private getQueryContext(
    domScope: ElementSelectorDOMScopeType,
    hostSelector: string,
    baseContext: Document | HTMLElement,
  ): Document | HTMLElement | ShadowRoot | null {
    switch (domScope) {
      case ElementSelectorDOMScopeType.Document:
        return document

      case ElementSelectorDOMScopeType.ShadowRoot:
        if (!hostSelector) {
          logger.warn(`[${this.name}] Shadow DOM 查询需要 hostSelector`)
          return null
        }
        return this.getShadowRootContext(hostSelector, baseContext)

      case ElementSelectorDOMScopeType.Iframe:
        if (!hostSelector) {
          logger.warn(`[${this.name}] Iframe 查询需要 hostSelector`)
          return null
        }
        return this.getIframeContext(hostSelector)

      default:
        return baseContext
    }
  }

  /**
   * 获取 Shadow Root 上下文
   */
  private getShadowRootContext(
    hostSelector: string,
    baseContext: Document | HTMLElement,
  ): ShadowRoot | null {
    try {
      const $hostElement = $(baseContext).find(hostSelector)

      if (!$hostElement || $hostElement.length === 0) {
        logger.debug(`[${this.name}] 未找到 Shadow Host: ${hostSelector}`)
        return null
      }

      const shadowRoot = $hostElement[0].shadowRoot
      if (!shadowRoot) {
        logger.warn(`[${this.name}] Shadow Host 没有 shadow root: ${hostSelector}`)
        return null
      }

      return shadowRoot
    }
    catch (error) {
      logger.warn(`[${this.name}] 获取 Shadow Root 失败: ${hostSelector}`, error)
      return null
    }
  }

  /**
   * 获取 Iframe 上下文
   */
  private getIframeContext(hostSelector: string): Document | null {
    try {
      const iframe = document.querySelector(hostSelector) as HTMLIFrameElement

      if (!iframe) {
        logger.warn(`[${this.name}] 未找到 Iframe: ${hostSelector}`)
        return null
      }

      const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document
      if (!iframeDoc) {
        logger.warn(`[${this.name}] 无法访问 Iframe 文档: ${hostSelector}`)
        return null
      }

      return iframeDoc
    }
    catch (error) {
      logger.warn(`[${this.name}] 获取 Iframe 上下文失败: ${hostSelector}`, error)
      return null
    }
  }

  /**
   * 获取 jQuery 查询上下文
   */
  private getJQueryQueryContext(
    domScope: ElementSelectorDOMScopeType,
    hostSelector: string,
    baseContext: Document | HTMLElement,
  ): JQuery<Document | HTMLElement> {
    switch (domScope) {
      case ElementSelectorDOMScopeType.Document:
        return $(document)

      case ElementSelectorDOMScopeType.ShadowRoot:
        if (!hostSelector) {
          logger.warn(`[${this.name}] Shadow DOM 查询需要 hostSelector`)
          return $(baseContext)
        }
        return this.getJQueryShadowContext(hostSelector, baseContext)

      case ElementSelectorDOMScopeType.Iframe:
        if (!hostSelector) {
          logger.warn(`[${this.name}] Iframe 查询需要 hostSelector`)
          return $(baseContext)
        }
        return this.getJQueryIframeContext(hostSelector)

      default:
        return $(baseContext)
    }
  }

  /**
   * 获取 jQuery Shadow DOM 上下文
   */
  private getJQueryShadowContext(
    hostSelector: string,
    baseContext: Document | HTMLElement,
  ): JQuery<Document | HTMLElement> {
    try {
      const shadowRoot = this.getShadowRootContext(hostSelector, baseContext)

      if (!shadowRoot)
        return $(baseContext)

      // 将 ShadowRoot 包装为 jQuery 对象
      return $(shadowRoot as any)
    }
    catch (error) {
      logger.warn(`[${this.name}] 获取 jQuery Shadow 上下文失败: ${hostSelector}`, error)
      return $(baseContext)
    }
  }

  /**
   * 获取 jQuery Iframe 上下文
   */
  private getJQueryIframeContext(hostSelector: string): JQuery<Document> {
    try {
      const iframeDoc = this.getIframeContext(hostSelector)
      if (!iframeDoc) {
        return $(document)
      }

      return $(iframeDoc)
    }
    catch (error) {
      logger.warn(`[${this.name}] 获取 jQuery Iframe 上下文失败: ${hostSelector}`, error)
      return $(document)
    }
  }

  /**
   * 查询 Shadow DOM 中的元素（jQuery 方式）
   */
  private queryShadowDOMWithJQuery(
    hostSelector: string,
    selector: string,
    $context: JQuery<Document | HTMLElement>,
  ): JQuery<HTMLElement> {
    try {
      // 先找到 Shadow Host
      const $host = ToolKit.ui.shadow.isShadowHost($context as JQuery<HTMLElement>)
        ? $context
        : ($(hostSelector, $context) as JQuery<HTMLElement>)

      if ($host.length === 0 || !ToolKit.ui.shadow.isShadowHost($host as JQuery<HTMLElement>))
        return $()

      // 在 Shadow Root 中查询
      return $host.find(selector)
    }
    catch (error) {
      logger.warn(`[${this.name}] Shadow DOM jQuery 查询失败: ${hostSelector} -> ${selector}`, error)
      return $()
    }
  }

  /**
   * 选择最优的查询引擎
   */
  private chooseOptimalEngine(selectorType: ElementSelectorType): ElementSelectorEngine {
    // 对于简单选择器，优先使用原生 API
    const nativeOptimizedTypes = [
      ElementSelectorType.Id,
      ElementSelectorType.Class,
      ElementSelectorType.Tag,
      ElementSelectorType.Attribute,
    ]

    return nativeOptimizedTypes.includes(selectorType)
      ? ElementSelectorEngine.Native
      : ElementSelectorEngine.Jquery
  }
}

/**
 * 元素查询函数工厂
 */
export interface ElementQueryFunction {
  (selector: string, queryOptions?: ElementQueryOptions): ElementQueryResult
}

function createElementQueryFunction(options?: ElementQueryOptions): ElementQueryFunction {
  const defaultOptions: ElementQueryOptions = {
    engine: ElementSelectorEngine.Jquery,
    returnType: ElementSelectorReturnType.Element,
  }

  return (selector: string, queryOptions?: ElementQueryOptions): ElementQueryResult => {
    const finalOptions = {
      ...defaultOptions,
      ...options,
      ...queryOptions,
    }

    return ElementQuery.getInstance().queryElement(selector, finalOptions)
  }
}

/**
 * 默认元素查询函数
 */
export const queryElement: ElementQueryFunction = createElementQueryFunction()

/**
 * 查询元素函数的快捷函数：返回单个元素或 null
 * 1）主要为了支持 jQuery 语法
 */
export function queryHTMLElement(selector: string, options?: ElementQueryOptions): HTMLElement | null {
  const result = queryElement(selector, {
    ...options,
    returnType: ElementSelectorReturnType.Element,
  })

  return result instanceof HTMLElement ? result : null
}

/**
 * 查询 jQuery 对象的快捷函数：返回多个元素或 null
 */
export function queryJQuery(selector: string, options?: ElementQueryOptions): JQuery<HTMLElement> {
  const result = queryElement(selector, {
    ...options,
    returnType: ElementSelectorReturnType.JQueryElement,
  })

  return result && (result as any).jquery ? result as JQuery<HTMLElement> : emptyJQuery()
}

/**
 * 查询 NodeList 的快捷函数：返回多个元素或 null
 */
export function queryNodeList(selector: string, options?: ElementQueryOptions): NodeList | null {
  const result = queryElement(selector, {
    ...options,
    returnType: ElementSelectorReturnType.NodeList,
  }) as NodeList | null

  return result && typeof result === 'object' && 'length' in result ? result : null
}
